#include "StdAfx.h"
#include "ExtListCtrl.h"

#ifdef _DEBUG
#define new new( _NORMAL_BLOCK, __FILE__, __LINE__)  
#endif

CExtListCtrl::CExtListCtrl(void)
{
	m_nRowHeight = 23;
	m_clrItemBk = RGB(54, 60, 76);
	m_clrListBk = RGB(54, 60, 76);
	m_clrListText = RGB(255, 255, 255);
	m_clrSelRowBk = RGB(68,168,253);			
	m_clrSelRowText = RGB(255, 255, 255); 
	m_bEnableGrid = TRUE;
	m_bEnableBorder = TRUE;
	m_clrGridLine = RGB(74, 80, 99);	
	m_clrBorder = RGB(74, 80, 99);	
    m_iAllItemHeight = 0;
    m_iItemWidth     = 0;
	m_fontText.CreateFont(18, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_TT_PRECIS, 
		CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "微软雅黑" );
}
CExtListCtrl::~CExtListCtrl(void)
{
	CTVector<SListItemProp*>::Destroy(m_vectorProps);
	CTVector<SListItemColor*>::Destroy(m_vectorClrItem);
	CTVector<SListAllColColor*>::Destroy(m_vectorClrAllCol);
	CTVector<SListAllRowColor*>::Destroy(m_vectorClrAllRow);
	
	m_fontText.DeleteObject();

}

BEGIN_MESSAGE_MAP(CExtListCtrl, CListCtrl)
	ON_WM_MEASUREITEM_REFLECT()	
	ON_WM_PAINT()
	ON_WM_NCPAINT()
	ON_WM_ERASEBKGND()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
    ON_WM_MOUSEWHEEL()
END_MESSAGE_MAP()

void CExtListCtrl::ReplaceHeader()
{
	CHeaderCtrl *pHeader = GetHeaderCtrl();
	m_listHeader.SubclassWindow(pHeader->GetSafeHwnd());
}
void CExtListCtrl::SetHeaderHeight(int nHeaderHeight)
{
	m_listHeader.SetHeaderHeight(nHeaderHeight);
}
void CExtListCtrl::SetHeaderBkColor(COLORREF clrHeaderBk)
{
	m_listHeader.SetHeaderBkColor(clrHeaderBk);
}
void CExtListCtrl::SetHeaderTextColor(COLORREF clrHeaderText)
{
	m_listHeader.SetHeaderTextColor(clrHeaderText);
}
void CExtListCtrl::SetHeaderBorder(BOOL bEnableBorder, COLORREF clrHeadBorder, UINT nPixel)
{
	m_listHeader.SetHeaderBorder(bEnableBorder, clrHeadBorder, nPixel);
} 
void CExtListCtrl::SetHeaderFont(int nFontHeight, BOOL bBold/* = FALSE*/)
{
	m_listHeader.SetHeaderFont(nFontHeight, bBold);
}

void CExtListCtrl::SetListGrid(BOOL bEnableGrid, COLORREF clrDivLine)
{
	m_listHeader.SetHeaderDivline(bEnableGrid, clrDivLine, 1);
	m_bEnableGrid = bEnableGrid;
	m_clrGridLine = clrDivLine;
}
void CExtListCtrl::SetListBorder( BOOL bEnableBorder, COLORREF clrBorder )
{
	m_listHeader.SetHeaderBorder(bEnableBorder, clrBorder, 1);
	m_bEnableBorder = bEnableBorder;
	m_clrBorder = clrBorder;
}

void CExtListCtrl::GetEveryItemRect( int nRow, int nCol, int nArea, CRect& rect )
{
	ASSERT(nRow >= 0);
	ASSERT(nCol >= 0);
	GetSubItemRect(nRow, nCol, nArea, rect);
	if (nCol == 0)
	{
		CRect rcTmp;
		GetSubItemRect(nRow, nCol+1, nArea, rcTmp);
		rect.right = rcTmp.left-1;
	}
}

INT CExtListCtrl::GetColumnCount()
{
	return GetHeaderCtrl()->GetItemCount();
}

void CExtListCtrl::MeasureItem( LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	if (m_nRowHeight > 0)
	{
		lpMeasureItemStruct->itemHeight = m_nRowHeight;
	}
}
void CExtListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	if (!m_listHeader.GetSafeHwnd()){		
		return ;
	}

	COLORREF clrItemText, clrItemBk;
	CRect	rcClient, rcItem, rcClipBox;	
	CDC		MemDC;
	CBitmap	BmpMem;
	CDC*	pDC = NULL; 
	CRect	rect;
	BOOL	bCombobox = FALSE;

	GetClientRect(&rcClient);
	rcItem = lpDrawItemStruct->rcItem;
    m_iAllItemHeight  = rcItem.bottom;
    m_iItemWidth      = rcItem.right;
	pDC = CDC::FromHandle(lpDrawItemStruct->hDC);	
	MemDC.CreateCompatibleDC(pDC);
	BmpMem.CreateCompatibleBitmap(pDC, rcItem.Width(), rcItem.Height());		//创建画布
	MemDC.SelectObject(&BmpMem);

	m_nDrawItemOffset = -rcItem.left;

	//得到绘画区域
	MemDC.GetClipBox(&rcClipBox);

	//获取属性
	int	nItemID = lpDrawItemStruct->itemID;
	int nColumnCount = m_listHeader.GetItemCount();
	
	clrItemText = m_clrListText;
	//画整行颜色
	
 	MemDC.FillSolidRect(rcClipBox, m_clrListBk);
	
	//绘画子项
	if (lpDrawItemStruct->itemAction == ODA_DRAWENTIRE)
	{
		//获取位置 
		for (int i = 0; i < nColumnCount; i++)
		{
			GetEveryItemRect(nItemID, i, LVIR_BOUNDS, rect);
			rect.OffsetRect(-rcItem.left, -rect.top);

			FindItemColor(nItemID, i, clrItemBk, clrItemText);
			MemDC.FillSolidRect(rect, clrItemBk);

			FindItemProp(nItemID, i, bCombobox);

			DrawListItemText(&MemDC, nItemID, i, rect, clrItemText, bCombobox);
		}
	}
	//鼠标选中一行高亮
	if (lpDrawItemStruct->itemState & ODS_SELECTED)
	{
		CRect	rect;
		
		GetEveryItemRect(nItemID, nColumnCount-1, LVIR_BOUNDS, rect);
		rect.OffsetRect(-rcItem.left, -rect.top);
		rect.left = rcClipBox.left;
		MemDC.FillSolidRect(rect, m_clrSelRowBk);
		for (int i = 0; i < nColumnCount; i++)
		{
			GetEveryItemRect(nItemID, i, LVIR_BOUNDS, rect);
			rect.OffsetRect(-rcItem.left, -rect.top);

			FindItemProp(nItemID, i, bCombobox);
			DrawListItemText(&MemDC, nItemID, i, rect, m_clrSelRowText, bCombobox);
		}
	}
	if (m_bEnableGrid){
		DrawGridLine(&MemDC, nItemID);
	}

	pDC->BitBlt(rcItem.left, rcItem.top, rcItem.Width(), rcItem.Height(), &MemDC, 0, 0, SRCCOPY);	

	BmpMem.DeleteObject();
	MemDC.DeleteDC();

}

void CExtListCtrl::DrawAllow( CDC *pDC, CRect rect, COLORREF clrAllow )
{
#define		SIZE_ALLOW			3
	Point		points[3];
	Pen			pen(Color(GetRValue(clrAllow), GetGValue(clrAllow), GetBValue(clrAllow)), 1);
	SolidBrush	sb(Color(GetRValue(clrAllow), GetGValue(clrAllow), GetBValue(clrAllow)));
	Graphics	gs(pDC->GetSafeHdc());

	points[0].X = rect.right - rect.Height()/2 + 5;
	points[0].Y = rect.top + (rect.Height() - SIZE_ALLOW)/2;
	points[1].X = points[0].X - 2*SIZE_ALLOW;
	points[1].Y = points[0].Y;
	points[2].X = points[0].X - SIZE_ALLOW;
	points[2].Y = points[0].Y + SIZE_ALLOW;
	gs.DrawPolygon(&pen, points, 3);
	gs.FillPolygon(&sb, points, 3);
}
void CExtListCtrl::DrawListItemText( CDC *pDC, int nItem, int nSubItem, CRect rcItem, COLORREF clrText, BOOL bCombobox )
{
	CString szText;
	HDITEM	hditem;
	UINT	nFmt;
	UINT	nFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS;
	CRect	rcArrow;

	hditem.mask = HDI_FORMAT;
	GetHeaderCtrl()->GetItem(nSubItem, &hditem);
	nFmt = hditem.fmt & HDF_JUSTIFYMASK;
	if (nFmt == HDF_CENTER){
		nFormat |= DT_CENTER;
	}
	else if (nFmt == HDF_LEFT){
		nFormat |= DT_LEFT;
	}
	else{
		nFormat |= DT_RIGHT;
	}

	szText = GetItemText(nItem, nSubItem);

	if(bCombobox)
	{
		rcArrow = rcItem;
		rcArrow.top += 1;
		rcArrow.bottom -= 1;
		rcArrow.left = rcArrow.right - 7;		// line up checkbox with header checkbox
		DrawAllow(pDC, rcArrow, clrText);
		rcItem.right = rcArrow.left - 4;
	}

	rcItem.left += 4;
	rcItem.right -= 4;
	pDC->SelectObject(&m_fontText);
	//pDC->SetBkMode(TRANSPARENT);
	pDC->SetTextColor(clrText);
	pDC->DrawText(szText, rcItem, nFormat);
}
void CExtListCtrl::FindItemProp(int nRow, int nCol, BOOL& bCombobox)
{
	UINT i = 0;

	bCombobox = FALSE;
	for (i = 0; i < m_vectorProps.size(); i++)
	{
		if ((m_vectorProps[i]->nRow == nRow) && (m_vectorProps[i]->nCol == nCol))
		{
			bCombobox = m_vectorProps[i]->bCombobox;
			return ;
		}
	}
}
void CExtListCtrl::FindItemColor( int nRow, int nCol, COLORREF& clrItemBk, COLORREF& clrItemText )
{
	//优先： Item > col > row > list
	UINT i = 0;
	for (i = 0; i < m_vectorClrItem.size(); i++)
	{
		if ((m_vectorClrItem[i]->nRow == nRow) && (m_vectorClrItem[i]->nCol == nCol))
		{
			clrItemBk = m_vectorClrItem[i]->clrItem;
			clrItemText = m_vectorClrItem[i]->clrText;
			return ;
		}
	}

	for (i = 0; i < m_vectorClrAllCol.size(); i++)
	{
		if ((m_vectorClrAllCol[i]->nCol == nCol))
		{
			clrItemBk = m_vectorClrAllCol[i]->clrAllCol;
			clrItemText = m_vectorClrAllCol[i]->clrText;
			return ;
		}
	}

	for (i = 0; i < m_vectorClrAllRow.size(); i++)
	{
		if ((m_vectorClrAllRow[i]->nRow == nRow))
		{
			clrItemBk = m_vectorClrAllRow[i]->clrAllRow;
			clrItemText = m_vectorClrAllRow[i]->clrText;
			return ;
		}
	}
	clrItemBk = m_clrListBk;
	clrItemText = m_clrListText;
}

void CExtListCtrl::DrawGridLine(CDC *pDC, int nItemID)
{
	CRect	rcClient, rcItem;
	Pen		pen(Color(255, GetRValue(m_clrGridLine), GetGValue(m_clrGridLine), GetBValue(m_clrGridLine)), 1);

	GetClientRect(&rcClient);
	Graphics gs(pDC->GetSafeHdc());
	//每列
	for (int i = 0; i < GetHeaderCtrl()->GetItemCount(); i++)
	{
		GetHeaderCtrl()->GetItemRect(i, &rcItem);
		gs.DrawLine(&pen, rcItem.left, rcClient.top, rcItem.left, rcClient.bottom);
	}
	//该行
	GetItemRect(nItemID, rcItem, LVIR_BOUNDS);
	rcItem.OffsetRect(m_nDrawItemOffset, -rcItem.top);
	gs.DrawLine(&pen, rcItem.left, rcItem.bottom-1, rcItem.right, rcItem.bottom-1);

}
void CExtListCtrl::DrawBorder( CDC *pDC )
{
	CRect	rcClient;
	Pen		pen(Color(255, GetRValue(m_clrBorder), GetGValue(m_clrBorder), GetBValue(m_clrBorder)), 1);
	GetClientRect(&rcClient);
	Graphics gs(pDC->GetSafeHdc());
	m_listHeader.SetHeaderBorder(TRUE, m_clrBorder, 1);
	gs.DrawRectangle(&pen, rcClient.left, rcClient.top, rcClient.Width()-4, rcClient.Height()-4);
}

void CExtListCtrl::SetItemHeight(int nHeight)			//设置行高
{
	CRect		rcWin;
	WINDOWPOS	winPos;

	if (nHeight > 0)
	{
		m_nRowHeight = nHeight;
	}

	GetWindowRect(&rcWin);
	winPos.hwnd = m_hWnd;
	winPos.cx = rcWin.Width();
	winPos.cy = rcWin.Height();
	winPos.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
	SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&winPos);   
}
void CExtListCtrl::SetListBkColor(COLORREF clrListBk)
{
	m_clrListBk = clrListBk;
	Invalidate();
}
void CExtListCtrl::SetListTextColor( COLORREF clrListText )
{
	m_clrListText = clrListText;
	Invalidate();
}

void CExtListCtrl::SetItemColor( int nRow, int nCol, COLORREF clrText, COLORREF clrItemBk )
{
	ASSERT(nRow >= 0);
	ASSERT(nCol >= 0);
	SListItemColor*  pItem = NULL;

	for (UINT i = 0; i < m_vectorClrItem.size(); i++)
	{
		if ((m_vectorClrItem[i]->nRow == nRow) && (m_vectorClrItem[i]->nCol == nCol))
		{
			m_vectorClrItem[i]->clrItem = clrItemBk;
			m_vectorClrItem[i]->clrText = clrText;
			Invalidate();
			return ;
		}
	}

	pItem = new SListItemColor;
	pItem->nRow = nRow;
	pItem->nCol = nCol;
	pItem->clrItem = clrItemBk;
	pItem->clrText = clrText;
	m_vectorClrItem.push_back(pItem);
	Invalidate();
}

BOOL CExtListCtrl::GetItemColor(int nRow,int nCol, COLORREF& clrText, COLORREF& clrItemBk)
{
	clrText = RGB(0,0,0);
	clrItemBk = RGB(0,0,0);

	ASSERT(nRow >= 0);
	ASSERT(nRow < GetItemCount());
	if ((nRow < 0) || nRow >= GetItemCount())
		return FALSE;
	ASSERT(nCol >= 0);
	ASSERT(nCol < GetHeaderCtrl()->GetItemCount());
	if ((nCol < 0) || nCol >= GetHeaderCtrl()->GetItemCount())
		return FALSE;

	for (UINT i = 0; i < m_vectorClrItem.size(); i++)
	{
		if ((m_vectorClrItem[i]->nRow == nRow) && (m_vectorClrItem[i]->nCol == nCol))
		{
			clrItemBk = m_vectorClrItem[i]->clrItem;
			clrText = m_vectorClrItem[i]->clrText;
			return TRUE;
		}
	}

	return FALSE;
}

void CExtListCtrl::SetItemCombobox( int nRow, int nCol, BOOL bCombobox )
{
	ASSERT(nRow >= 0);
	ASSERT(nCol >= 0);
	SListItemProp*  pItem = NULL;

	for (UINT i = 0; i < m_vectorProps.size(); i++)
	{
		if ((m_vectorProps[i]->nRow == nRow) && (m_vectorProps[i]->nCol == nCol))
		{
			m_vectorProps[i]->bCombobox = bCombobox;
			Invalidate();
			return ;
		}
	}

	pItem = new SListItemProp;
	pItem->nRow = nRow;
	pItem->nCol = nCol;
	pItem->bCombobox = bCombobox;
	m_vectorProps.push_back(pItem);
	Invalidate();
}
void CExtListCtrl::SetAllRowColor( COLORREF clrAllRow, COLORREF clrText, int nRow )
{
	ASSERT(nRow >= 0);
	SListAllRowColor*  pAllRow = NULL;

	for (UINT i = 0; i < m_vectorClrAllRow.size(); i++)
	{
		if (m_vectorClrAllRow[i]->nRow == nRow)
		{
			m_vectorClrAllRow[i]->clrAllRow = clrAllRow;
			m_vectorClrAllRow[i]->clrText = clrText;
			Invalidate();
			return ;
		}
	}

	pAllRow = new SListAllRowColor;
	pAllRow->nRow = nRow;
	pAllRow->clrAllRow = clrAllRow;
	pAllRow->clrText = clrText;
	m_vectorClrAllRow.push_back(pAllRow);
	Invalidate();
}
void CExtListCtrl::SetAllColColor( COLORREF clrAllCol, COLORREF clrText, int nCol )
{
	ASSERT(nCol >= 0);
	SListAllColColor*  pAllCol = NULL;

	for (UINT i = 0; i < m_vectorClrAllCol.size(); i++)
	{
		if (m_vectorClrAllCol[i]->nCol == nCol)
		{
			m_vectorClrAllCol[i]->clrAllCol = clrAllCol;
			m_vectorClrAllCol[i]->clrText = clrText;
			Invalidate();
			return ;
		}
	}

	pAllCol = new SListAllColColor;
	pAllCol->nCol = nCol;
	pAllCol->clrAllCol = clrAllCol;
	pAllCol->clrText = clrText;
	m_vectorClrAllCol.push_back(pAllCol);
	Invalidate();
}
void CExtListCtrl::SetSelRowColor( COLORREF clrSelRowBk, COLORREF clrSelRowText )
{
	m_clrSelRowBk = clrSelRowBk;
	m_clrSelRowText = clrSelRowText;
}

void CExtListCtrl::SetFont( int nFontHeight, BOOL bBold /*= FALSE*/ )
{
	m_fontText.DeleteObject();
	m_fontText.CreateFont(nFontHeight, 0, 0, 0, bBold ? FW_BOLD : FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_TT_PRECIS, 
		CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "微软雅黑" );
	Invalidate();
}

BOOL CExtListCtrl::OnEraseBkgnd( CDC* pDC )
{	
    CRect	rect;
    CDC		memDC;
    CBitmap memBmp;
    GetClientRect(rect);

    memDC.CreateCompatibleDC(pDC);
    memBmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    memDC.SelectObject(&memBmp);

    memDC.FillSolidRect(rect, m_clrListBk);
    if (m_bEnableBorder){
        DrawBorder(&memDC);
    }

    pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
	return TRUE;
}
void CExtListCtrl::PreSubclassWindow()
{
	CListCtrl::PreSubclassWindow();
	m_HScroll.InitScrollBar(this, SB_HORZ);
	m_VScroll.InitScrollBar(this, SB_VERT);
}
void CExtListCtrl::OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
{
	m_HScroll.SendMessage(WM_MSG_SCROLLCHANGED, (WPARAM)SB_HORZ, (LPARAM)nSBCode);
	CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
    CRect   rect;
    GetClientRect(rect);
    rect.top = m_iAllItemHeight;
    InvalidateRect(rect);
}
BOOL CExtListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	GetParent()->SendMessage(WM_MSG_SCROLLCHANGED, (WPARAM)this,NULL);
    short   zRate = zDelta/120;
    if(zRate > 0)
    {
        while(zRate--)
        {
            if(m_VScroll.IsWindowVisible())
            {
                SendMessage(WM_VSCROLL,SB_LINEUP,NULL);
                continue;
            }
            if(m_HScroll.IsWindowVisible())
            {
                SendMessage(WM_HSCROLL,SB_LINELEFT,NULL);
                continue;
            }
        }     
    }
    else
    {
        while(zRate++)
        {
            if(m_VScroll.IsWindowVisible())
            {
                SendMessage(WM_VSCROLL,SB_LINEDOWN,NULL);
                continue;
            }
            if(m_HScroll.IsWindowVisible())
            {
                SendMessage(WM_HSCROLL,SB_LINERIGHT,NULL);
                continue;
            }          
        }     
    }
    return TRUE;
}

void CExtListCtrl::OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
{
	m_VScroll.SendMessage(WM_MSG_SCROLLCHANGED, (WPARAM)SB_VERT, (LPARAM)nSBCode);	
	GetParent()->SendMessage(WM_MSG_SCROLLCHANGED, NULL,NULL);
	CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
    CRect   rect;
    GetClientRect(rect);
    rect.left = m_iItemWidth;
    InvalidateRect(rect);
}
void CExtListCtrl::OnPaint()
{
    CListCtrl::OnPaint();
    m_HScroll.UpdateScrollBar();
    m_VScroll.UpdateScrollBar();
  
}
void CExtListCtrl::OnNcPaint()
{
	CWindowDC dc(this);
}

BOOL CExtListCtrl::DeleteAllItems()
{
	CTVector<SListItemProp*>::Destroy(m_vectorProps);
	CTVector<SListItemColor*>::Destroy(m_vectorClrItem);
	CTVector<SListAllColColor*>::Destroy(m_vectorClrAllCol);
	CTVector<SListAllRowColor*>::Destroy(m_vectorClrAllRow);
	return CListCtrl::DeleteAllItems();
}
BOOL CExtListCtrl::DeleteItem( int nItem )
{
	if (nItem < 0 || nItem >= GetItemCount())
	{
		return FALSE;
	}

	for (UINT i = 0; i < m_vectorClrAllRow.size(); i++)
	{
		if (m_vectorClrAllRow[i]->nRow == nItem)
		{
			CTVector<SListAllRowColor*>::Delete(m_vectorClrAllRow, i);
			break;
		}
	}
	for (UINT i = 0; i < m_vectorClrItem.size(); i++)
	{
		if (m_vectorClrItem[i]->nRow == nItem)
		{
			CTVector<SListItemColor*>::Delete(m_vectorClrItem, i);
			break;
		}
	}

	return CListCtrl::DeleteItem(nItem);
}
BOOL CExtListCtrl::DeleteColumn( int nCol )
{
	for (UINT i = 0; i < m_vectorClrAllRow.size(); i++)
	{
		if (m_vectorClrAllCol[i]->nCol == nCol)
		{
			CTVector<SListAllColColor*>::Delete(m_vectorClrAllCol, i);
			break;
		}
	}
	for (UINT i = 0; i < m_vectorClrItem.size(); i++)
	{
		if (m_vectorClrItem[i]->nCol == nCol)
		{
			CTVector<SListItemColor*>::Delete(m_vectorClrItem, i);
			break;
		}
	}
	return CListCtrl::DeleteColumn(nCol);
}


